home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / mxlibs / smixw122 / smix.c < prev    next >
C/C++ Source or Header  |  1995-05-27  |  23KB  |  813 lines

  1. /*      SMIXW is Copyright 1995 by Ethan Brodsky.  All rights reserved      */
  2.  
  3. /* █ smix.c v1.22 █████████████████████████████████████████████████████████ */
  4.  
  5. #define TRUE  1
  6. #define FALSE 0
  7.  
  8. #define ON  1
  9. #define OFF 0
  10.  
  11. #define BLOCK_LENGTH    512   /* Length of digitized sound output block     */
  12. #define VOICES          8     /* Number of available simultaneous voices    */
  13. #define VOLUMES         64    /* Number of volume levels for sound output   */
  14.  
  15. typedef struct
  16.   {
  17.     signed   char *soundptr;
  18.     unsigned long soundsize;
  19.   } SOUND;
  20.  
  21. int  init_sb(int baseio, int irq, int dma, int dma16);
  22.   /* Initializes control parameters, resets DSP and installs int. handler   */
  23.   /*  Parameters:                                                           */
  24.   /*   baseio    Sound card base IO address                                 */
  25.   /*   irq       Sound card IRQ setting                                     */
  26.   /*   dma       Sound card 8-bit DMA channel                               */
  27.   /*   dma16     Sound card 16-bit DMA channel                              */
  28.   /*  Returns:                                                              */
  29.   /*   TRUE      Sound card successfully initialized                        */
  30.   /*   FALSE     Sound card could not be initialized                        */
  31.  
  32. void shutdown_sb(void);
  33.   /* Removes interrupt handler and resets DSP                               */
  34.  
  35.  
  36. void init_mixing(void);
  37.   /* Allocates internal buffers and starts digitized sound output           */
  38.  
  39. void shutdown_mixing(void);
  40.   /* Deallocates internal buffers and stops digitized sound output          */
  41.  
  42.  
  43. void load_sound(SOUND **sound, char *filename);
  44.   /* Allocates an extended memory block and loads a sound from a file       */
  45.   /*  Parameters:                                                           */
  46.   /*   sound     Pointer to pointer to unallocated sound data structure     */
  47.   /*   filename  Pointer to character string containing filename            */
  48.  
  49. void free_sound(SOUND **sound);
  50.   /* Frees sound data structure and extended memory block                   */
  51.   /*  Parameters:                                                           */
  52.   /*   sound     Pointer to pointer to allocated sound data structure       */
  53.  
  54.  
  55. void start_sound(SOUND *sound, int index, unsigned char volume, int loop);
  56.   /* Starts playing a sound                                                 */
  57.   /*  Parameters:                                                           */
  58.   /*   sound     Pointer to sound data structure                            */
  59.   /*   index     A number to keep track of the sound with (Used to stop it) */
  60.   /*   loop      Indicates whether sound should be continuously looped      */
  61.  
  62. void stop_sound(int index);
  63.   /* Stops playing a sound                                                  */
  64.   /*  Parameters:                                                           */
  65.   /*   index     Index of sound to stop (All with given index are stopped)  */
  66.  
  67. int  sound_playing(int index);
  68.   /* Checks if a sound is still playing                                     */
  69.   /*  Parameters:                                                           */
  70.   /*   index     Index used when the sound was started                      */
  71.   /*  Returns:                                                              */
  72.   /*   TRUE      At least one sound with the specified index is playing     */
  73.   /*   FALSE     No sounds with the specified index are playing             */
  74.  
  75.  
  76. void set_sound_volume(unsigned char new_volume);
  77.   /* Sets overall sound volume                                              */
  78.   /*  Parameters:                                                           */
  79.   /*   new_volume  New overall sound volume (0-255)                         */
  80.  
  81. volatile long intcount;               /* Current count of sound interrupts  */
  82. volatile int  voicecount;             /* Number of voices currently in use  */
  83.  
  84. float dspversion;
  85. int   autoinit;
  86. int   sixteenbit;
  87.  
  88. /* ████████████████████████████████████████████████████████████████████████ */
  89.  
  90. #include <dos.h>
  91. #include <i86.h>
  92. #include <stdio.h>
  93. #include <stdlib.h>
  94.  
  95. #include "lowmem.h"
  96.  
  97. #define BUFFER_LENGTH BLOCK_LENGTH*2
  98.  
  99. #define BYTE unsigned char
  100.  
  101. #define lo(value) (unsigned char)((value) & 0x00FF)
  102. #define hi(value) (unsigned char)((value) >> 8)
  103.  
  104. #define MAX(a, b) (((a) > (b)) ? (a) : (b))
  105. #define MIN(a, b) (((a) > (b)) ? (b) : (a))
  106.  
  107. int resetport;
  108. int readport;
  109. int writeport;
  110. int pollport;
  111. int ackport;
  112.  
  113. int pic_rotateport;
  114. int pic_maskport;
  115.  
  116. int dma_maskport;
  117. int dma_clrptrport;
  118. int dma_modeport;
  119. int dma_addrport;
  120. int dma_countport;
  121. int dma_pageport;
  122.  
  123. char irq_startmask;
  124. char irq_stopmask;
  125. char irq_intvector;
  126.  
  127. char dma_startmask;
  128. char dma_stopmask;
  129. char dma_mode;
  130.  
  131. void (interrupt far *oldintvector)(void);
  132.  
  133. int handler_installed;
  134.  
  135. void write_dsp(BYTE value)
  136.   {
  137.     while ((inp(writeport) & 0x80));
  138.     outp(writeport, value);
  139.   }
  140.  
  141. BYTE read_dsp(void)
  142.   {
  143.     while (!(inp(pollport) & 0x80));
  144.     return(inp(readport));
  145.   }
  146.  
  147. int reset_dsp(void)
  148.   {
  149.     int i;
  150.  
  151.     outp(resetport, 1);
  152.     for (i=0; i < 100; i++)    /* The delay function doesn't work correctly */
  153.       { };
  154.     outp(resetport, 0);
  155.  
  156.     i = 100;
  157.     while ((i-- > 0) && (read_dsp() != 0xAA));
  158.  
  159.     return(i > 0);
  160.   }
  161.  
  162. void install_handler(void);
  163. void uninstall_handler(void);
  164. void mix_exitproc(void);
  165.  
  166. int init_sb(int baseio, int irq, int dma, int dma16)
  167.   {
  168.    /* Sound card IO ports */
  169.     resetport  = baseio + 0x006;
  170.     readport   = baseio + 0x00A;
  171.     writeport  = baseio + 0x00C;
  172.     pollport   = baseio + 0x00E;
  173.  
  174.    /* Reset DSP, get version, choose output mode */
  175.     if (!reset_dsp())
  176.       return(FALSE);
  177.     write_dsp(0xE1);  /* Get DSP version number */
  178.     dspversion = read_dsp();  dspversion += read_dsp() / 100.0;
  179.     autoinit   = (dspversion > 2.0);
  180.     sixteenbit = (dspversion > 4.0) && (dma16 != 0);
  181.  
  182.    /* Compute interrupt controller ports and parameters */
  183.     if (irq < 8)
  184.       { /* PIC1 */
  185.         irq_intvector  = 0x08 + irq;
  186.         pic_rotateport = 0x20;
  187.         pic_maskport   = 0x21;
  188.       }
  189.     else
  190.       { /* PIC2 */
  191.         irq_intvector  = 0x70 + irq-8;
  192.         pic_rotateport = 0xA0;
  193.         pic_maskport   = 0xA1;
  194.       }
  195.     irq_stopmask  = 1 << (irq % 8);
  196.     irq_startmask = ~irq_stopmask;
  197.  
  198.    /* Compute DMA controller ports and parameters */
  199.     if (sixteenbit)
  200.       { /* Sixteen bit */
  201.         dma_maskport   = 0xD4;
  202.         dma_clrptrport = 0xD8;
  203.         dma_modeport   = 0xD6;
  204.         dma_addrport   = 0xC0 + 4*(dma16-4);
  205.         dma_countport  = 0xC2 + 4*(dma16-4);
  206.         switch (dma16)
  207.           {
  208.             case 5:
  209.               dma_pageport = 0x8B;
  210.               break;
  211.             case 6:
  212.               dma_pageport = 0x89;
  213.               break;
  214.             case 7:
  215.               dma_pageport = 0x8A;
  216.               break;
  217.           }
  218.         dma_stopmask  = dma16-4 + 0x04;  /* 000001xx */
  219.         dma_startmask = dma16-4 + 0x00;  /* 000000xx */
  220.         if (autoinit)
  221.           dma_mode = dma16-4 + 0x58;     /* 010110xx */
  222.         else
  223.           dma_mode = dma16-4 + 0x48;     /* 010010xx */
  224.         ackport = baseio + 0x00F;
  225.       }
  226.     else
  227.       { /* Eight bit */
  228.         dma_maskport   = 0x0A;
  229.         dma_clrptrport = 0x0C;
  230.         dma_modeport   = 0x0B;
  231.         dma_addrport   = 0x00 + 2*dma;
  232.         dma_countport  = 0x01 + 2*dma;
  233.         switch (dma)
  234.           {
  235.             case 0:
  236.               dma_pageport = 0x87;
  237.               break;
  238.             case 1:
  239.               dma_pageport = 0x83;
  240.               break;
  241.             case 2:
  242.               dma_pageport = 0x81;
  243.               break;
  244.             case 3:
  245.               dma_pageport = 0x82;
  246.               break;
  247.           }
  248.         dma_stopmask  = dma + 0x04;      /* 000001xx */
  249.         dma_startmask = dma + 0x00;      /* 000000xx */
  250.         if (autoinit)
  251.           dma_mode    = dma + 0x58;      /* 010110xx */
  252.         else
  253.           dma_mode    = dma + 0x48;      /* 010010xx */
  254.         ackport = baseio + 0x00E;
  255.       }
  256.     install_handler();
  257.     atexit(mix_exitproc);
  258.  
  259.     return(TRUE);
  260.   }
  261.  
  262. void shutdown_sb(void)
  263.   {
  264.     if (handler_installed) uninstall_handler();
  265.     reset_dsp();
  266.   }
  267.  
  268. /* Voice control */
  269.  
  270. typedef struct
  271.   {
  272.     SOUND *sound;
  273.     int   index;
  274.     int   volume;
  275.     int   loop;
  276.     long  curpos;
  277.     int   done;
  278.   } VOICE;
  279.  
  280. int   inuse[VOICES];
  281. VOICE voice[VOICES];
  282.  
  283. int curblock;
  284.  
  285. /* Volume lookup table */
  286. signed int (*volume_table)[VOLUMES][256];
  287.  
  288. /* Mixing buffer */
  289. signed int  mixingblock[BLOCK_LENGTH];  /* Signed 16 bit */
  290.  
  291. /* Output buffers */
  292. void          (*outmemarea)                = NULL;  /* Twice buffer size */
  293. unsigned char (*out8buf)[2][BLOCK_LENGTH]  = NULL;  /* Unsigned 8 bit    */
  294. signed  short (*out16buf)[2][BLOCK_LENGTH] = NULL;  /* Signed 16 bit     */
  295.  
  296. void *blockptr[2];
  297.  
  298. short int outmemarea_sel;               /* Selector for output buffer */
  299.  
  300. /* Addressing for auto-initialized transfers (Whole buffer)   */
  301. unsigned long buffer_addr;
  302. unsigned char buffer_page;
  303. unsigned int  buffer_ofs;
  304.  
  305. /* Addressing for single-cycle transfers (One block at a time */
  306. unsigned long block_addr[2];
  307. unsigned char block_page[2];
  308. unsigned int  block_ofs[2];
  309.  
  310. int handler_installed;
  311.  
  312. unsigned char sound_volume;
  313.  
  314. /* 8-bit clipping */
  315.  
  316. unsigned char (*clip_8_buf)[256*VOICES];
  317. unsigned char (*clip_8)[256*VOICES];
  318.  
  319. void start_dac(void)
  320.   {
  321.     if (autoinit)
  322.       { /* Auto init DMA */
  323.         outp(dma_maskport,   dma_stopmask);
  324.         outp(dma_clrptrport, 0x00);
  325.         outp(dma_modeport,   dma_mode);
  326.         outp(dma_addrport,   lo(buffer_ofs));
  327.         outp(dma_addrport,   hi(buffer_ofs));
  328.         outp(dma_countport,  lo(BUFFER_LENGTH-1));
  329.         outp(dma_countport,  hi(BUFFER_LENGTH-1));
  330.         outp(dma_pageport,   buffer_page);
  331.         outp(dma_maskport,   dma_startmask);
  332.       }
  333.     else
  334.       { /* Single cycle DMA */
  335.         outp(dma_maskport,   dma_stopmask);
  336.         outp(dma_clrptrport, 0x00);
  337.         outp(dma_modeport,   dma_mode);
  338.         outp(dma_addrport,   lo(buffer_ofs));
  339.         outp(dma_addrport,   hi(buffer_ofs));
  340.         outp(dma_countport,  lo(BLOCK_LENGTH-1));
  341.         outp(dma_countport,  hi(BLOCK_LENGTH-1));
  342.         outp(dma_pageport,   buffer_page);
  343.         outp(dma_maskport,   dma_startmask);
  344.       }
  345.  
  346.     if (sixteenbit)
  347.       { /* Sixteen bit auto-initialized: SB16 and up (DSP 4.xx)             */
  348.         write_dsp(0x41);                /* Set sound output sampling rate   */
  349.         write_dsp(hi(22050));
  350.         write_dsp(lo(22050));
  351.         write_dsp(0xB6);                /* 16-bit cmd  - D/A - A/I - FIFO   */
  352.         write_dsp(0x10);                /* 16-bit mode - signed mono        */
  353.         write_dsp(lo(BLOCK_LENGTH-1));
  354.         write_dsp(hi(BLOCK_LENGTH-1));
  355.       }
  356.     else
  357.       { /* Eight bit */
  358.         if (autoinit)
  359.           { /* Eight bit auto-initialized:  SBPro and up (DSP 2.00+)        */
  360.             write_dsp(0xD1);            /* Turn on speaker                  */
  361.             write_dsp(0x40);            /* Set sound output time constant   */
  362.             write_dsp(211);             /*  = 256 - (1000000 / rate)        */
  363.             write_dsp(0x48);            /* Set DSP block transfer size      */
  364.             write_dsp(lo(BLOCK_LENGTH-1));
  365.             write_dsp(hi(BLOCK_LENGTH-1));
  366.             write_dsp(0x1C);            /* 8-bit auto-init DMA mono output  */
  367.           }
  368.         else
  369.           { /* Eight bit single-cycle:  Sound Blaster (DSP 1.xx+)           */
  370.             write_dsp(0xD1);            /* Turn on speaker                  */
  371.             write_dsp(0x40);            /* Set sound output time constant   */
  372.             write_dsp(211);             /*  = 256 - (1000000 / rate)        */
  373.             write_dsp(0x14);            /* 8-bit single-cycle DMA output    */
  374.             write_dsp(lo(BLOCK_LENGTH-1));
  375.             write_dsp(hi(BLOCK_LENGTH-1));
  376.           }
  377.       }
  378.   }
  379.  
  380. void stop_dac(void)
  381.   {
  382.     if (sixteenbit)
  383.       write_dsp(0xD5);                  /* Pause 16-bit DMA sound I/O       */
  384.     else
  385.       {
  386.         write_dsp(0xD0);                /* Pause 8-bit DMA sound I/O        */
  387.         write_dsp(0xD3);                /* Turn off speaker                 */
  388.       }
  389.  
  390.     outp(dma_maskport, dma_stopmask);   /* Stop DMA                         */
  391.   }
  392.  
  393. /* Volume control */
  394.  
  395. void init_volume_table(void)
  396.   {
  397.     unsigned int  volume;
  398.     signed   int  insample;
  399.     signed   char invalue;
  400.  
  401.     volume_table = malloc(VOLUMES * 256 * sizeof(signed int));
  402.  
  403.     for (volume=0; volume < VOLUMES; volume++)
  404.       for (insample = -128; insample <= 127; insample++)
  405.         {
  406.           invalue = insample;
  407.           (*volume_table)[volume][(unsigned char)invalue] =
  408.             (((float)volume/(float)(VOLUMES-1)) * 32 * invalue);
  409.         }
  410.  
  411.     sound_volume = 255;
  412.   }
  413.  
  414. void set_sound_volume(unsigned char new_volume)
  415.   {
  416.     sound_volume = new_volume;
  417.   }
  418.  
  419. /* Mixing initialization */
  420.  
  421. void init_clip8(void)
  422.   {
  423.     int i;
  424.     int value;
  425.  
  426.     clip_8_buf = malloc(256*VOICES);
  427.     clip_8     = (char *)clip_8_buf + 128*VOICES;
  428.  
  429.     for (i = -128*VOICES; i < 128*VOICES; i++)
  430.       {
  431.         value = i;
  432.         value = max(value, -128);
  433.         value = min(value, 127);
  434.  
  435.         (*clip_8)[i] = value + 128;
  436.       }
  437.   }
  438.  
  439. unsigned long linear_addr(void *ptr)
  440.   {
  441.     return((unsigned long)(ptr));
  442.   }
  443.  
  444. void deallocate_voice(int voicenum);
  445.  
  446. void init_mixing(void)
  447.   {
  448.     int i;
  449.  
  450.     for (i=0; i < VOICES; i++)
  451.       deallocate_voice(i);
  452.     voicecount = 0;
  453.  
  454.     if (sixteenbit)
  455.       {
  456.        /* Find a block of memory that does not cross a page boundary */
  457.         out16buf = outmemarea =
  458.           low_malloc(4*BUFFER_LENGTH, &outmemarea_sel);
  459.  
  460.         if ((((linear_addr(out16buf) >> 1) % 65536) + BUFFER_LENGTH) > 65536)
  461.           out16buf += BUFFER_LENGTH;
  462.  
  463.         for (i=0; i<2; i++)
  464.           blockptr[i] = &((*out16buf)[i]);
  465.  
  466.        /* DMA parameters */
  467.         buffer_addr = linear_addr(out16buf);
  468.         buffer_page = buffer_addr        / 65536;
  469.         buffer_ofs  = (buffer_addr >> 1) % 65536;
  470.  
  471.         memset(out16buf, 0x00, BUFFER_LENGTH * sizeof(signed short));
  472.       }
  473.     else
  474.       {
  475.        /* Find a block of memory that does not cross a page boundary */
  476.         out8buf = outmemarea =
  477.           low_malloc(2*BUFFER_LENGTH, &outmemarea_sel);
  478.  
  479.         if (((linear_addr(out8buf) % 65536) + BUFFER_LENGTH) > 65536)
  480.           out8buf += BUFFER_LENGTH;
  481.  
  482.         for (i=0; i<2; i++)
  483.           blockptr[i] = &((*out8buf)[i]);
  484.  
  485.        /* DMA parameters */
  486.         buffer_addr = linear_addr(out8buf);
  487.         buffer_page = buffer_addr / 65536;
  488.         buffer_ofs  = buffer_addr % 65536;
  489.         for (i=0; i<2; i++)
  490.           {
  491.             block_addr[i] = linear_addr(blockptr[i]);
  492.             block_page[i] = block_addr[i] / 65536;
  493.             block_ofs[i]  = block_addr[i] % 65536;
  494.           }
  495.         memset(out8buf, 0x80, BUFFER_LENGTH * sizeof(unsigned char));
  496.  
  497.         init_clip8();
  498.  
  499.       }
  500.  
  501.     curblock = 0;
  502.     intcount = 0;
  503.  
  504.     init_volume_table();
  505.     start_dac();
  506.   }
  507.  
  508. void shutdown_mixing(void)
  509.   {
  510.     stop_dac();
  511.  
  512.     free(volume_table);
  513.  
  514.     if (!sixteenbit) free(clip_8_buf);
  515.  
  516.     low_free(outmemarea_sel);
  517.   }
  518.  
  519. /* Loading and freeing sounds */
  520.  
  521. void load_sound(SOUND **sound, char *filename)
  522.   {
  523.     FILE *f;
  524.     long size;
  525.  
  526.    /* Open file and compute size */
  527.     f = fopen(filename, "rb");
  528.     fseek(f, 0, SEEK_END);  /* Move to end of file */
  529.     size = ftell(f);        /* File size = end pos */
  530.     fseek(f, 0, SEEK_SET);  /* Back to begining    */
  531.  
  532.    /* Allocate sound control structure and sound data block */
  533.     (*sound) = (SOUND *) malloc(sizeof(SOUND));
  534.     (*sound)->soundptr  = (signed char *)(malloc(size));
  535.     (*sound)->soundsize = size;
  536.  
  537.    /* Read sound data and close file (Isn't flat mode nice?) */
  538.     fread((*sound)->soundptr, sizeof(signed char), size, f);
  539.     fclose(f);
  540.   }
  541.  
  542. void free_sound(SOUND **sound)
  543.   {
  544.     free((*sound)->soundptr);
  545.     free(*sound);
  546.     *sound = NULL;
  547.   }
  548.  
  549. /* Voice maintainance */
  550.  
  551. void deallocate_voice(int voicenum)
  552.   {
  553.     inuse[voicenum] = FALSE;
  554.     voice[voicenum].sound  = NULL;
  555.     voice[voicenum].index  = -1;
  556.     voice[voicenum].volume = 0;
  557.     voice[voicenum].curpos = -1;
  558.     voice[voicenum].loop   = FALSE;
  559.     voice[voicenum].done   = FALSE;
  560.   }
  561.  
  562. void start_sound(SOUND *sound, int index, unsigned char volume, int loop)
  563.   {
  564.     int i, voicenum;
  565.  
  566.     voicenum = -1;
  567.     i = 0;
  568.  
  569.     do
  570.       {
  571.         if (!inuse[i])
  572.           voicenum = i;
  573.         i++;
  574.       }
  575.     while ((voicenum == -1) && (i < VOICES));
  576.  
  577.     if (voicenum != -1)
  578.       {
  579.         voice[voicenum].sound  = sound;
  580.         voice[voicenum].index  = index;
  581.         voice[voicenum].volume = volume;
  582.         voice[voicenum].curpos = 0;
  583.         voice[voicenum].loop   = loop;
  584.         voice[voicenum].done   = FALSE;
  585.  
  586.         inuse[voicenum] = TRUE;
  587.         voicecount++;
  588.       }
  589.   }
  590.  
  591. void stop_sound(int index)
  592.   {
  593.     int i;
  594.  
  595.     for (i=0; i < VOICES; i++)
  596.       if (voice[i].index == index)
  597.         {
  598.           voicecount--;
  599.           deallocate_voice(i);
  600.         }
  601.   }
  602.  
  603. int  sound_playing(int index)
  604.   {
  605.     int i;
  606.  
  607.    /* Search for a sound with the specified index */
  608.     for (i=0; i < VOICES; i++)
  609.       if (voice[i].index == index)
  610.         return(TRUE);
  611.  
  612.    /* Sound not found */
  613.     return(FALSE);
  614.   }
  615.  
  616. void update_voices(void)
  617.   {
  618.     int voicenum;
  619.  
  620.     for (voicenum=0; voicenum < VOICES; voicenum++)
  621.       {
  622.         if (inuse[voicenum])
  623.           {
  624.             if (voice[voicenum].done)
  625.               {
  626.                 voicecount--;
  627.                 deallocate_voice(voicenum);
  628.               }
  629.           }
  630.       }
  631.   }
  632.  
  633. /* Mixing */
  634.  
  635. void mix_voice(int voicenum)
  636.   {
  637.     SOUND *sound;
  638.     int   mixlength;
  639.     signed char *sourceptr;
  640.     signed int *volume_lookup;
  641.     int chunklength;
  642.     int destindex;
  643.  
  644.    /* Initialization */
  645.     sound = voice[voicenum].sound;
  646.  
  647.     sourceptr = sound->soundptr + voice[voicenum].curpos;
  648.     destindex = 0;
  649.  
  650.    /* Compute mix length */
  651.     if (voice[voicenum].loop)
  652.       mixlength = BLOCK_LENGTH;
  653.     else
  654.       mixlength =
  655.        MIN(BLOCK_LENGTH, sound->soundsize - voice[voicenum].curpos);
  656.  
  657.     volume_lookup =
  658.      (signed int *)(&((*volume_table)[(unsigned char)((((sound_volume/256.0) * voice[voicenum].volume) * (VOLUMES/256.0)))]));
  659.  
  660.     do
  661.       {
  662.        /* Compute the max consecutive samples that can be mixed */
  663.         chunklength =
  664.          MIN(mixlength, sound->soundsize - voice[voicenum].curpos);
  665.  
  666.        /* Update the current position */
  667.         voice[voicenum].curpos += chunklength;
  668.  
  669.        /* Update the remaining samples count */
  670.         mixlength -= chunklength;
  671.  
  672.        /* Mix samples until end of mixing or end of sound data is reached */
  673.         while (chunklength--)
  674.           mixingblock[destindex++] += volume_lookup[(unsigned char)(*(sourceptr++))];
  675.  
  676.        /* If we've reached the end of the block, wrap to start of sound */
  677.         if (sourceptr == (sound->soundptr + sound->soundsize))
  678.           {
  679.             if (voice[voicenum].loop)
  680.               {
  681.                 voice[voicenum].curpos = 0;
  682.                 sourceptr = sound->soundptr;
  683.               }
  684.             else
  685.               {
  686.                 voice[voicenum].done = TRUE;
  687.               }
  688.           }
  689.       }
  690.     while (mixlength); /* Wrap around to finish mixing if necessary */
  691.   }
  692.  
  693. void silenceblock(void)
  694.   {
  695.     memset(&mixingblock, 0x00, BLOCK_LENGTH*sizeof(signed int));
  696.   }
  697.  
  698. void mix_voices(void)
  699.   {
  700.     int i;
  701.  
  702.     silenceblock();
  703.  
  704.     for (i=0; i < VOICES; i++)
  705.       if (inuse[i])
  706.         mix_voice(i);
  707.   }
  708.  
  709. void copy_sound16(void)
  710.   {
  711.     int i;
  712.     signed short *destptr;
  713.  
  714.     destptr   = blockptr[curblock];
  715.  
  716.     for (i=0; i < BLOCK_LENGTH; i++)
  717.       destptr[i] = mixingblock[i];
  718.   }
  719.  
  720. void copy_sound8(void)
  721.   {
  722.     int i;
  723.     unsigned char *destptr;
  724.  
  725.     destptr   = blockptr[curblock];
  726.  
  727.     for (i=0; i < BLOCK_LENGTH; i++)
  728.       destptr[i] = (*clip_8)[mixingblock[i] >> 5];
  729.   }
  730.  
  731. void copy_sound(void)
  732.   {
  733.     if (sixteenbit)
  734.       copy_sound16();
  735.     else
  736.       copy_sound8();
  737.   }
  738.  
  739. void startblock_sc(void) /* Starts a single-cycle DMA transfer */
  740.   {
  741.     outp(dma_maskport,   dma_stopmask);
  742.     outp(dma_clrptrport, 0x00);
  743.     outp(dma_modeport,   dma_mode);
  744.     outp(dma_addrport,   lo(block_ofs[curblock]));
  745.     outp(dma_addrport,   hi(block_ofs[curblock]));
  746.     outp(dma_countport,  lo(BLOCK_LENGTH-1));
  747.     outp(dma_countport,  hi(BLOCK_LENGTH-1));
  748.     outp(dma_pageport,   block_page[curblock]);
  749.     outp(dma_maskport,   dma_startmask);
  750.     write_dsp(0x14);                /* 8-bit single-cycle DMA sound output  */
  751.     write_dsp(lo(BLOCK_LENGTH-1));
  752.     write_dsp(hi(BLOCK_LENGTH-1));
  753.   }
  754.  
  755. void interrupt inthandler(void)
  756.   {
  757.     intcount++;
  758.  
  759.     if (!autoinit)   /* Start next block quickly if not using auto-init DMA */
  760.       {
  761.         startblock_sc();
  762.         copy_sound();
  763.         curblock = !curblock;  /* Toggle block */
  764.       }
  765.  
  766.     update_voices();
  767.     mix_voices();
  768.  
  769.     if (autoinit)
  770.       {
  771.         copy_sound();
  772.         curblock = !curblock;  /* Toggle block */
  773.       }
  774.  
  775.     inp(ackport);       /* Acknowledge interrupt with sound card */
  776.     outp(0xA0, 0x20);   /* Acknowledge interrupt with PIC2 */
  777.     outp(0x20, 0x20);   /* Acknowledge interrupt with PIC1 */
  778.   }
  779.  
  780. void install_handler(void)
  781.   {
  782.     _disable();  /* CLI */
  783.     outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  784.  
  785.     oldintvector = _dos_getvect(irq_intvector);
  786.     _dos_setvect(irq_intvector, inthandler);
  787.  
  788.     outp(pic_maskport, (inp(pic_maskport) & irq_startmask));
  789.     _enable();   /* STI */
  790.  
  791.     handler_installed = TRUE;
  792.   }
  793.  
  794. void uninstall_handler(void)
  795.   {
  796.     _disable();  /* CLI */
  797.     outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
  798.  
  799.     _dos_setvect(irq_intvector, oldintvector);
  800.  
  801.     _enable();   /* STI */
  802.  
  803.     handler_installed = FALSE;
  804.   }
  805.  
  806. void mix_exitproc(void)
  807.   {
  808.     stop_dac();
  809.     shutdown_sb();
  810.   }
  811.  
  812. /* ████████████████████████████████████████████████████████████████████████ */
  813.